package cn.cas.mango.util.RequestUtil;

import cn.cas.mango.dto.param.QueryParam;
import cn.cas.mango.service.ConfigService;
import cn.cas.mango.util.RenderDateUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Like;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchPhrasePrefixQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchPhraseQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.MultiMatchQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders;
import co.elastic.clients.elasticsearch._types.query_dsl.QueryStringQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.RangeQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.TermQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.TermsQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.TextQueryType;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.search.Highlight;
import co.elastic.clients.elasticsearch.core.search.HighlightField;
import co.elastic.clients.elasticsearch.indices.Alias;
import co.elastic.clients.elasticsearch.indices.AnalyzeRequest;
import co.elastic.clients.elasticsearch.indices.AnalyzeResponse;

import co.elastic.clients.elasticsearch.indices.GetAliasResponse;
import co.elastic.clients.elasticsearch.indices.analyze.AnalyzeToken;
import co.elastic.clients.json.JsonData;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Component
@Slf4j
public class BuildRequest {
  @Autowired
  private ConfigService config;
  @Autowired
  private ElasticsearchClient client;
  public final String[] includesArray = new String[]{
      "news_title_zh", "news_author",
      "news_publictime", "news_publicdate", "news_website", "news_website_type",
      "news_content_zh", "id", "news_url", "news_type", "news_media_name", "news_keywords"
  };

  public final String[] baseArray = new String[]{
      "news_author",
      "news_publictime", "news_publicdate", "news_website", "news_website_type",
       "id", "news_url", "news_type", "news_media_name", "news_keywords"
  };

  private void setHighlight(String queryField,
                         Map<String, HighlightField> map,
                         String zh) {

    HighlightField contentField = HighlightField.of(
        f -> f.preTags("<span class=\"highlight\">").postTags("</span>").numberOfFragments(5)
            .fragmentSize(config.getFragmentSize()).boundaryMaxScan(10));
    HighlightField titleField = HighlightField.of(
        f -> f.preTags("<span class=\"highlight\">").postTags("</span>").numberOfFragments(2));
    switch (queryField) {
      case "content":
        map.put("news_content" + zh, contentField);
        break;
      case "title":
        map.put("news_title" + zh, titleField);
        break;
      default:
        map.put("news_title" + zh, titleField);
        map.put("news_content" + zh, contentField);
        break;
    }
  }

  private void setFields(String queryField,
                         List<String> fields,
                         String zh) {
    switch (queryField) {
      case "content":
        fields.add("news_content" + zh);
        break;
      case "title":
        fields.add("news_title" + zh);
        break;
      default:
        fields.add("news_title" + zh);
        fields.add("news_content" + zh);
        break;
    }
  }

  private void setHighlight(String queryField,
                         Map<String, HighlightField> map,
                         String zh,
                         Query.Builder highlightBuilder) {
    Query build = highlightBuilder.build();
    HighlightField contentField = HighlightField.of(
        f -> f.preTags("<span class=\"highlight\">").postTags("</span>").numberOfFragments(5)
            .fragmentSize(config.getFragmentSize()).boundaryMaxScan(10).highlightQuery(build));
    HighlightField titleField = HighlightField.of(
        f -> f.preTags("<span class=\"highlight\">").postTags("</span>").numberOfFragments(2)
            .highlightQuery(build));
    switch (queryField) {
      case "content":
        map.put("news_content" + zh, contentField);
        break;
      case "title":
        map.put("news_title" + zh, titleField);
        break;
      default:
        map.put("news_title" + zh, titleField);
        map.put("news_content" + zh, contentField);
        break;
    }
  }

  // true 需要变为zh
  private boolean judgeZh(String string) {
    AnalyzeRequest analyzeRequest = AnalyzeRequest.of(a->a.index(
        config.getRealIndex()).field("news_content_zh").text(string));
    try {
      AnalyzeResponse response = client.indices().analyze(analyzeRequest);
      List<AnalyzeToken> tokens = response.tokens();
      List<String> collect = tokens.stream().map(t -> t.token()).collect(Collectors.toList());
      log.info(collect.toString());
      if (collect.isEmpty()) {
        return true;
      }

      String firstType = tokens.get(0).type();
      String lastType = tokens.get(tokens.size() - 1).type();
      if (firstType.equals("CN_CHAR")) {
        return false;
      }
      if (lastType.equals("CN_CHAR")) {
        return false;
      }
      return true;
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  private boolean judgeZhArray(String[] strings) {
    if (strings == null || strings.length == 0) {
      return true;
    }
    String string = strings[0];
    log.info("{} analyze result:", string);
    return judgeZh(string);
  }

  public SearchRequest.Builder buildMltRequest(QueryParam queryParam) {
    List<String> fields = new ArrayList<>();
    Map<String, HighlightField> map = new HashMap<>();
    String queryField = queryParam.getQueryField();
    String queryStr = queryParam.getQueryStr().trim();
    boolean zh = true;
    String zhString = zh ? "_zh": "";
    queryParam.setZh(zh);

    List<String> includes = new ArrayList<>(Arrays.asList(baseArray));
    includes.add("news_content" + zhString);
    includes.add("news_title" + zhString);


    BoolQuery.Builder tempBool = new BoolQuery.Builder();
    setFields(queryField, fields, zhString);
    tempBool.must(m->m.moreLikeThis(
        v->v.fields(fields)
            .like(new ArrayList<Like>()
            {{
              add(
                  Like.of(f->f.document(
                      d->d.id(queryParam.get_id())
                          .index(partitionIndex(queryParam.getIndex(),
                              queryParam.getStartDate(), queryParam.getEndDate())))));
            }})
            .minDocFreq(config.getMltMinDocFreq())
            .minTermFreq(config.getMltMinTermFreq())
            .maxQueryTerms(config.getMltMaxQueryTerms())
    ));


    SearchRequest.Builder builder = new SearchRequest.Builder();
    RangeQuery rq;
    if (Strings.isNotBlank(queryParam.getStartDate()) && Strings.isNotBlank(
        queryParam.getEndDate())) {
      rq = RangeQuery.of(
          r -> r.field("news_publicdate").gte(JsonData.of(queryParam.getStartDate()))
              .lte(JsonData.of(queryParam.getEndDate())));
    } else if (Strings.isNotBlank(queryParam.getStartDate())) {
      rq = RangeQuery.of(
          r -> r.field("news_publicdate").gte(JsonData.of(queryParam.getStartDate())));
    } else if (Strings.isNotBlank(queryParam.getEndDate())) {
      rq = RangeQuery.of(
          r -> r.field("news_publicdate").lte(JsonData.of(queryParam.getEndDate())));
    } else {
      rq = null;
    }
    BoolQuery tempBoolQuery = tempBool.build();
    setNormal(builder, queryParam, queryStr, rq, tempBoolQuery, includes);

    if (queryParam.getPageSize() > 0) {
      Highlight.Builder h = new Highlight.Builder();
      setHighlight(queryField, map, zhString);
      h.fields(map);
      builder.highlight(h.build());
    }
    return builder;
  }


  public SearchRequest.Builder builderTopicRequest(QueryParam queryParam) {
    List<String> fields = new ArrayList<>();
    Map<String, HighlightField> map = new HashMap<>();
    String queryField = queryParam.getQueryField();
    String queryStr = queryParam.getQueryStr().trim();
    String[] splitQueryStr = queryStr.split("\\s+");
    boolean zh = true;
    String zhString = zh ? "_zh": "";
    queryParam.setZh(zh);

    List<String> includes = new ArrayList<>(Arrays.asList(baseArray));
    includes.add("news_content" + zhString);
    includes.add("news_title" + zhString);

    BoolQuery.Builder tempBool = new BoolQuery.Builder();
    setFields(queryField, fields, zhString);
    if (config.getTopicRecommendMode().startsWith("t")) {
      for (String query: splitQueryStr) {
        TermQuery termQuery = TermQuery.of(t ->
            t.field("news_keywords").value(query));
        tempBool.should(t->t.term(termQuery));
      }
    } else {
      for (String query: splitQueryStr) {
        MultiMatchQuery multiMatchQuery = MultiMatchQuery.of(
            v -> v.query(query).fields(fields).type(TextQueryType.PhrasePrefix)
        );
        MultiMatchQuery finalMultiMatchQuery = multiMatchQuery;
        tempBool.must(m->m.multiMatch(finalMultiMatchQuery));
      }
    }
    tempBool.minimumShouldMatch(config.getTopicLikeDegree());

    SearchRequest.Builder builder = new SearchRequest.Builder();
    RangeQuery rq;
    if (Strings.isNotBlank(queryParam.getStartDate()) && Strings.isNotBlank(
        queryParam.getEndDate())) {
      rq = RangeQuery.of(
          r -> r.field("news_publicdate").gte(JsonData.of(queryParam.getStartDate()))
              .lte(JsonData.of(queryParam.getEndDate())));
    } else if (Strings.isNotBlank(queryParam.getStartDate())) {
      rq = RangeQuery.of(
          r -> r.field("news_publicdate").gte(JsonData.of(queryParam.getStartDate())));
    } else if (Strings.isNotBlank(queryParam.getEndDate())) {
      rq = RangeQuery.of(
          r -> r.field("news_publicdate").lte(JsonData.of(queryParam.getEndDate())));
    } else {
      rq = null;
    }
    BoolQuery tempBoolQuery = tempBool.build();
    setNormal(builder, queryParam, queryStr, rq, tempBoolQuery, includes);

    Highlight.Builder h = new Highlight.Builder();
    SearchRequest.Builder tempBuilder = new SearchRequest.Builder();
    setNormal(tempBuilder, queryParam, queryStr, rq, tempBoolQuery, includes);

    List<Query> ret = new ArrayList<>();
    for (String str: splitQueryStr) {
      MultiMatchQuery.Builder b = new MultiMatchQuery.Builder();
      b.fields(
          new ArrayList<String>(){{
            add("news_content_zh");
            add("news_title_zh");
          }});
      b.query(str);
      b.type(TextQueryType.Phrase);
      ret.add(b.build()._toQuery());
    }
    Query.Builder highlightQuery = new Query.Builder();
    highlightQuery.bool(b->b.must(ret));
    setHighlight(queryField, map, zhString, highlightQuery);

    h.fields(map);
    builder.highlight(h.build());

    return builder;
  }

  public SearchRequest.Builder buildRequest(QueryParam queryParam) {
    List<String> fields = new ArrayList<>();
    Map<String, HighlightField> map = new HashMap<>();
    String queryField = queryParam.getQueryField();
    String queryStr = queryParam.getQueryStr().trim();
    String[] splitQueryStr = queryStr.split("\\s+");
    boolean zh;
    if (queryParam.getSearchType().equals("false")) {
      zh = true;
    } else {
      zh = judgeZhArray(splitQueryStr);
    }
    String zhString = zh ? "_zh": "";
    queryParam.setZh(zh);

    List<String> includes = new ArrayList<>(Arrays.asList(baseArray));
    includes.add("news_content" + zhString);
    includes.add("news_title" + zhString);

    MultiMatchQuery multiMatchQuery = null;
    MatchPhrasePrefixQuery matchPhrasePrefixQuery = null;
    // 添加should 让更接近搜索的排在前面
    MultiMatchQuery multiShouldMatchQuery = null;
    MatchQuery matchQuery = null;

    BoolQuery.Builder tempBool = new BoolQuery.Builder();
    setFields(queryField, fields, zhString);
    if (queryField.equals("all")) {
      if (queryParam.getSearchType().equalsIgnoreCase("true")) {
    for (String query: splitQueryStr) {
          multiMatchQuery = MultiMatchQuery.of(
              v -> v.query(query).fields(fields).type(TextQueryType.PhrasePrefix)
          );
          MultiMatchQuery finalMultiMatchQuery = multiMatchQuery;
          tempBool.must(m->m.multiMatch(finalMultiMatchQuery));
        }

      } else {
        if (queryParam.getLikeDegree().charAt(0) == '0') {
          for (String query: splitQueryStr) {
            multiMatchQuery = MultiMatchQuery.of(
                v -> v.query(query).fields(fields).type(TextQueryType.BestFields));
            MultiMatchQuery finalMultiMatchQuery = multiMatchQuery;
            tempBool.must(m->m.multiMatch(finalMultiMatchQuery));
          }
        } else {

          if (queryParam.getRecommendType().charAt(0) == 'k'
              && config.getRecommendFieldType().equals("keywords")
          ) {
            fields.clear();
            fields.add("news_title_zh");
            fields.add("news_content_zh");
//            for (Map<String, Object> map_:  queryParam.getKeywordsWithScore()) {
//              String name = (String) map_.get("name");
//              Double value = (Double) map_.get("value");
//              multiMatchQuery = MultiMatchQuery.of(
//                  v -> v.query(name).fields(fields)
//                      .type(TextQueryType.PhrasePrefix)
//                      .boost(value.floatValue())
////                    .type(TextQueryType.CrossFields)
////                    .minimumShouldMatch(config.getFuzzyValue())
//              );
//              MultiMatchQuery finalMultiMatchQuery = multiMatchQuery;
//              tempBool.should(m -> m.multiMatch(finalMultiMatchQuery));
//            }
//            tempBool.minimumShouldMatch(queryParam.getLikeDegree());
            List<String> lists = new ArrayList<>();
            for (Map<String, Object> map_:  queryParam.getKeywordsWithScore()) {
              String name = (String) map_.get("name");
              Double value = (Double) map_.get("value");
              lists.add(name + "^" + String.format("%.2f", value));
            }
            String queryTemp;
            if (!lists.isEmpty()) {
              queryTemp = lists.stream().reduce((m1, m2) -> m1 + " " + m2).get();
            } else {
                queryTemp = queryStr;
            }
              QueryStringQuery query = QueryStringQuery.of(q->q.query(queryTemp).fields(fields)
                  .type(TextQueryType.Phrase).minimumShouldMatch(queryParam.getLikeDegree()).analyzer("whitespace"));
            tempBool.should(m -> m.queryString(query));
          } else {
            for (String query : splitQueryStr) {
              if (config.getRecommendFieldType().equals("keywords")) {
                TermQuery termQuery = TermQuery.of(t ->
                    t.field("news_entities").value(query));
                tempBool.should(t->t.term(termQuery));
              } else {
                multiMatchQuery = MultiMatchQuery.of(
                    v -> v.query(query).fields(fields)
                        .type(TextQueryType.Phrase)
//                    .type(TextQueryType.CrossFields)
//                    .minimumShouldMatch(config.getFuzzyValue())
                );
                MultiMatchQuery finalMultiMatchQuery = multiMatchQuery;
                tempBool.should(m -> m.multiMatch(finalMultiMatchQuery));
              }
            }
            tempBool.minimumShouldMatch(queryParam.getLikeDegree());
          }
        }
      }

    }
    else {
      if (queryParam.getSearchType().equalsIgnoreCase("true")) {
        for (String query: splitQueryStr) {
          matchPhrasePrefixQuery = MatchPhrasePrefixQuery.of(v -> v.query(query).field(fields.get(0)));
          MatchPhrasePrefixQuery finalMatchPhraseQuery = matchPhrasePrefixQuery;
          tempBool.must(m->m.matchPhrasePrefix(finalMatchPhraseQuery));
        }
      } else {

        for (String query: splitQueryStr) {
          matchQuery = MatchQuery.of(v -> v.query(query).field(fields.get(0)));
          MatchQuery finalMatchQuery = matchQuery;
          tempBool.must(m->m.match(finalMatchQuery));
        }
      }
    }
//    MultiMatchQuery finalMm = multiMatchQuery;
//    MultiMatchQuery finalMsm = multiShouldMatchQuery;
//    MatchPhrasePrefixQuery finalMp = matchPhrasePrefixQuery;
//    MatchQuery mq = matchQuery;
    SearchRequest.Builder builder = new SearchRequest.Builder();
    RangeQuery rq;
    if (Strings.isNotBlank(queryParam.getStartDate()) && Strings.isNotBlank(
        queryParam.getEndDate())) {
      rq = RangeQuery.of(
          r -> r.field("news_publicdate").gte(JsonData.of(queryParam.getStartDate()))
              .lte(JsonData.of(queryParam.getEndDate())));
    } else if (Strings.isNotBlank(queryParam.getStartDate())) {
      rq = RangeQuery.of(
          r -> r.field("news_publicdate").gte(JsonData.of(queryParam.getStartDate())));
    } else if (Strings.isNotBlank(queryParam.getEndDate())) {
      rq = RangeQuery.of(
          r -> r.field("news_publicdate").lte(JsonData.of(queryParam.getEndDate())));
    } else {
      rq = null;
    }
    BoolQuery tempBoolQuery = tempBool.build();
    setNormal(builder, queryParam, queryStr, rq, tempBoolQuery, includes);

    if (queryParam.getLikeDegree().charAt(0) != '0' && queryParam.getRecommendType().charAt(0) == 'k'
        && config.getRecommendFieldType().equals("keywords")) {
      Highlight.Builder h = new Highlight.Builder();
      SearchRequest.Builder tempBuilder = new SearchRequest.Builder();
      setNormal(tempBuilder, queryParam, queryStr, rq, tempBoolQuery, includes);
      setHighlight(queryField, map, zhString);
      h.fields(map);
      builder.highlight(h.build());
      return builder;
    }


    if (queryParam.getPageSize() > 0) {

      Highlight.Builder h = new Highlight.Builder();
      SearchRequest.Builder tempBuilder = new SearchRequest.Builder();
      setNormal(tempBuilder, queryParam, queryStr, rq, tempBoolQuery, includes);


      List<Query> temp = tempBuilder.build().query().bool().must();

      if ((queryParam.getSearchType().equals("true") || !queryParam.getLikeDegree().startsWith("0")) && temp != null
          && !temp.isEmpty() && queryParam.isZh()) {
        Query query = temp.get(0);
        List<Query> must = query.bool().must();
        List<Query> ret = new ArrayList<>();
        if (fields.size() == 2) {
          if (!queryParam.getLikeDegree().startsWith("0")) {
            for (String str: splitQueryStr) {
              MultiMatchQuery.Builder b = new MultiMatchQuery.Builder();
              b.fields(
                  new ArrayList<String>(){{
                    add("news_content_zh");
                    add("news_title_zh");
                  }});
              b.query(str);
              b.type(TextQueryType.Phrase);
              ret.add(b.build()._toQuery());
            }
          } else {
            must.forEach(x-> {
              MultiMatchQuery multiMatchQuery1 = x.multiMatch();

              MultiMatchQuery.Builder b = new MultiMatchQuery.Builder();
              b.query(multiMatchQuery1.query());
              b.fields(
                  new ArrayList<String>(){{
                    add("news_content_zh");
                    add("news_title_zh");
                  }});
              b.type(TextQueryType.Phrase);
              ret.add(b.build()._toQuery());
            });
          }
        } else {
          must.forEach(x-> {
            MatchPhrasePrefixQuery matchPhrasePrefixQuery1 = x.matchPhrasePrefix();
            MultiMatchQuery.Builder b = new MultiMatchQuery.Builder();
            b.query(matchPhrasePrefixQuery1.query());
            b.fields(
                new ArrayList<String>(){{
                  add("news_content_zh");
                  add("news_title_zh");
                }});
            b.type(TextQueryType.Phrase);
            ret.add(b.build()._toQuery());
          });
        }

        Query.Builder highlightQuery = new Query.Builder();
        highlightQuery.bool(b->b.must(ret));
        setHighlight(queryField, map, zhString, highlightQuery);
      } else {
        setHighlight(queryField, map, zhString);
      }
      h.fields(map);
      builder.highlight(h.build());
    }
    return builder;
  }

  public String partitionIndex(String index, String startDate, String endDate) {
    String alias = config.getAliasIndex();
    if (index.equals(config.getPersonIndex())) {
      return index;
    }
    if (Strings.isBlank(startDate) || Strings.isBlank(endDate)) {
      return alias;
    }
    String prefixIndex = config.getIndex();
    return returnIndex(prefixIndex, startDate, endDate);
  }

  public String returnIndex(String prefixIndex, String startDate, String endDate) {
    String[] split = prefixIndex.split(",");
    List<String> monthsBetween = RenderDateUtil.getMonthsBetween(startDate, endDate);
    Set<String> ret = new HashSet<>();
    for (String pi: split) {
      ret.addAll(monthsBetween.stream().map(x -> pi + x).collect(Collectors.toList()));
    }

    Set<String> alias;
    try {
      alias = getAlias();
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
    ret.retainAll(alias);
    return String.join(",", ret);
  }

  public  Set<String> getAlias() throws IOException {
    GetAliasResponse aliasResponse = client.indices().getAlias(r -> r.name(config.getAliasIndex()));
    return aliasResponse.result().keySet();
  }

  private void setNormal(SearchRequest.Builder builder, QueryParam queryParam, String queryStr,
                         RangeQuery rq, BoolQuery tempBoolQuery, List<String> includes) {
    builder
        .index(partitionIndex(getIndex(queryParam), queryParam.getStartDate(), queryParam.getEndDate()))
        .query(QueryBuilders.bool(bool ->
            {
              BoolQuery.Builder b;
              // 如果有询问ids
              if (!queryParam.getIdsArray().isEmpty()) {
//               bool.filter(x->x.ids(IdsQuery.of(i->i.values(queryParam.getIdsArray()))));
                bool.filter(x->x.terms(t->t.field("id").terms(terms->terms.value(queryParam.getIdsArray()))));
              }
              if (Strings.isBlank(queryStr)) {
                if (rq != null) {
                  b = bool.filter(f -> f.range(rq));
                } else {
                  b = bool;
                }
              } else {
                if (rq != null) {
                  b = bool.must(must -> must.bool(tempBoolQuery))
//                        .should(should -> should.multiMatch(finalMsm))
                      .filter(f -> f.range(rq));
                } else {
                  b = bool.must(must -> must.bool(tempBoolQuery))
//                        .should(should -> should.multiMatch(finalMsm))
                  ;
                }
              }

              List<FieldValue> webSiteTypeArray = queryParam.getWebSiteTypeArray();
              if (webSiteTypeArray != null && !webSiteTypeArray.isEmpty()) {
                TermsQuery sq1 = TermsQuery.of(
                    t -> t.field("news_website_type").terms(x -> x.value(webSiteTypeArray)));
                b = b.filter(f -> f.terms(sq1));
              }
              List<FieldValue> webSitesArray = queryParam.getWebSitesArray();
              if (webSitesArray != null && !webSitesArray.isEmpty()) {
                TermsQuery sq2 = TermsQuery.of(
                    t -> t.field("news_website").terms(x -> x.value(webSitesArray)));
                b = b.filter(f -> f.terms(sq2));
              }
              if (Strings.isNotBlank(queryParam.getType())) {
                TermQuery tq = TermQuery.of(t -> t.field("news_type").value(queryParam.getType()));
                b.filter(f -> f.term(tq));
              }
              return b;
            }
        ))
        .from((queryParam.getCurrentPage() - 1) * queryParam.getPageSize())
        .size(queryParam.getPageSize())
        .trackTotalHits(c -> c.count(config.getHitsCount()))
        .source(source -> source.filter(f -> f.includes(includes)));
//    if (queryParam.getSearchType().equalsIgnoreCase("true")) {
//      if (!StringUtils.containsAny(queryStr, config.getExactSearchSpecialSymbol())) {
//          builder = builder.postFilter(p->p.script(s->s.script(m->m.inline(f->f.source(
//              String.format("doc['news_title_zh'].value.contains('%s')" +
//                  " || doc['news_content_zh'].value.contains('%s')", queryStr, queryStr)
//          ).lang("painless")))));
//      }
//    }

  }


  private String getIndex(QueryParam queryParam) {
    return Strings.isNotBlank(queryParam.getSourceSearchType())? queryParam.getBiIndex(): config.getIndex();
  }

  public SearchRequest.Builder buildQueryStrRequest(QueryParam queryParam) {
    List<String> fields = new ArrayList<>();
    String queryField = queryParam.getQueryField();
    Map<String, HighlightField> map = new HashMap<>();
    List<String> includes = Arrays.asList(includesArray);
    queryParam.setZh(true);
    setFields(queryField, fields, "_zh");
    setHighlight(queryField, map, "_zh");
    RangeQuery rq;
    if (Strings.isNotBlank(queryParam.getStartDate()) && Strings.isNotBlank(
        queryParam.getEndDate())) {
      rq = RangeQuery.of(
          r -> r.field("news_publicdate").gte(JsonData.of(queryParam.getStartDate()))
              .lte(JsonData.of(queryParam.getEndDate())));
    } else if (Strings.isNotBlank(queryParam.getStartDate())) {
      rq = RangeQuery.of(
          r -> r.field("news_publicdate").gte(JsonData.of(queryParam.getStartDate())));
    } else if (Strings.isNotBlank(queryParam.getEndDate())) {
      rq = RangeQuery.of(
          r -> r.field("news_publicdate").lte(JsonData.of(queryParam.getEndDate())));
    } else {
      rq = null;
    }
    SearchRequest.Builder builder = new SearchRequest.Builder();
    builder.index(partitionIndex(getIndex(queryParam),queryParam.getStartDate(), queryParam.getEndDate()))
        .query(
            query -> query.bool(
                bool -> {
                  if (!queryParam.getIdsArray().isEmpty()) {
//               bool.filter(x->x.ids(IdsQuery.of(i->i.values(queryParam.getIdsArray()))));
                    bool.filter(x->x.terms(t->t.field("id").terms(terms->terms.value(queryParam.getIdsArray()))));
                  }
                  List<FieldValue> webSiteTypeArray = queryParam.getWebSiteTypeArray();
                  if (webSiteTypeArray != null && !webSiteTypeArray.isEmpty()) {
                    TermsQuery sq1 = TermsQuery.of(
                        t -> t.field("news_website_type").terms(x -> x.value(webSiteTypeArray)));
                    bool = bool.filter(f -> f.terms(sq1));
                  }
                  List<FieldValue> webSitesArray = queryParam.getWebSitesArray();
                  if (webSitesArray != null && !webSitesArray.isEmpty()) {
                    TermsQuery sq2 = TermsQuery.of(
                        t -> t.field("news_website").terms(x -> x.value(webSitesArray)));
                    bool = bool.filter(f -> f.terms(sq2));
                  }
                  if (Strings.isNotBlank(queryParam.getType())) {
                    TermQuery tq = TermQuery.of(t -> t.field("news_type").value(queryParam.getType()));
                    bool.filter(f -> f.term(tq));
                  }
                  if (rq != null) {
                    return bool.must(
                            must -> must.queryString(
                                queryString -> queryString.query(
                                        queryParam.getQueryStr())
                                    .minimumShouldMatch(queryParam.getLikeDegree())
                                    .fields(
                                        fields
                                    ).boost(config.getBoost()).analyzer(config.getAnalyzer())
                            )
                        )
                        .filter(f -> f.range(rq));
                  } else {
                    return bool.must(
                        must -> must.queryString(
                            queryString -> queryString.query(
                                    queryParam.getQueryStr())
                                .minimumShouldMatch(queryParam.getLikeDegree())
                                .fields(
                                    fields
                                ).boost(config.getBoost()).analyzer(config.getAnalyzer())
                        )
                    );
                  }
                }
            )
        )
        .source(source -> source.filter(f -> f.includes(includes)))
        .from((queryParam.getCurrentPage() - 1) * queryParam.getPageSize())
        .size(queryParam.getPageSize())
        .trackTotalHits(c -> c.count(config.getHitsCount()));

    if (queryParam.getPageSize() > 0) {
      builder.highlight(hi -> hi.fields(map));
    }
    return builder;
  }

  public SearchRequest.Builder buildBiSearchRequest(QueryParam queryParam) {
    List<String> fields = new ArrayList<>();
    Map<String, HighlightField> map = new HashMap<>();
    String queryField = queryParam.getQueryField();
    String queryStr = queryParam.getQueryStr().trim();
    String[] splitQueryStr = queryStr.split("\\s+");
    queryParam.setSourceSearchType("person");
    boolean zh = true;
    String zhString = "_zh";
    queryParam.setZh(true);

    List<String> includes = new ArrayList<>(Arrays.asList(baseArray));
    includes.add("news_content" + zhString);
    includes.add("news_title" + zhString);

    BoolQuery.Builder tempBool = new BoolQuery.Builder();
    List<FieldValue> collect = Arrays.stream(splitQueryStr).map(x -> FieldValue.of(x)).collect(Collectors.toList());
    tempBool.must(m->m.terms(t->t.field("news_entities_person").terms(tt->tt.value(collect))));
    setFields(queryField, fields, zhString);

    SearchRequest.Builder builder = new SearchRequest.Builder();
    RangeQuery rq;
    if (Strings.isNotBlank(queryParam.getStartDate()) && Strings.isNotBlank(
        queryParam.getEndDate())) {
      rq = RangeQuery.of(
          r -> r.field("news_publicdate").gte(JsonData.of(queryParam.getStartDate()))
              .lte(JsonData.of(queryParam.getEndDate())));
    } else if (Strings.isNotBlank(queryParam.getStartDate())) {
      rq = RangeQuery.of(
          r -> r.field("news_publicdate").gte(JsonData.of(queryParam.getStartDate())));
    } else if (Strings.isNotBlank(queryParam.getEndDate())) {
      rq = RangeQuery.of(
          r -> r.field("news_publicdate").lte(JsonData.of(queryParam.getEndDate())));
    } else {
      rq = null;
    }
    BoolQuery tempBoolQuery = tempBool.build();
    setNormal(builder, queryParam, queryStr, rq, tempBoolQuery, includes);

    if (queryParam.getPageSize() > 0) {

      Highlight.Builder h = new Highlight.Builder();
      SearchRequest.Builder tempBuilder = new SearchRequest.Builder();
      setNormal(tempBuilder, queryParam, queryStr, rq, tempBoolQuery, includes);

      List<Query> ret = new ArrayList<>();


      Query query = Query.of(q ->
          q.queryString(v -> v.query("+(" + Strings.join(Arrays.asList(splitQueryStr).stream()
                  .map(m->"\"" + m + "\"").collect(Collectors.toList()), ' ') + ")")
              .fields(new ArrayList<String>(){{
            add("news_content_zh");
            add("news_title_zh");
          }}).type(TextQueryType.Phrase)
              .analyzer(config.getAnalyzer())));
      ret.add(query);
      Query.Builder highlightQuery = new Query.Builder();
      highlightQuery.bool(b->b.must(ret));
      setHighlight(queryField, map, zhString, highlightQuery);

      h.fields(map);
      builder.highlight(h.build());
    }
    return builder;
  }


  public SearchRequest.Builder buildKeywordsLikeRequest(QueryParam queryParam) {
    List<String> fields = new ArrayList<>();
    String queryField = "all";
    String queryStr = queryParam.getQueryStr().trim();
    String[] splitQueryStr = queryStr.split("\\s+");
    boolean zh = true;
    String zhString = zh ? "_zh": "";
    queryParam.setZh(zh);

    List<String> includes = new ArrayList<>(Arrays.asList(baseArray));
    includes.add("news_content" + zhString);
    includes.add("news_title" + zhString);

    MultiMatchQuery multiMatchQuery;


    BoolQuery.Builder tempBool = new BoolQuery.Builder();
    setFields(queryField, fields, zhString);


    for (String query : splitQueryStr) {
        multiMatchQuery = MultiMatchQuery.of(
                v -> v.query(query).fields(fields).type(TextQueryType.CrossFields)
//                    .minimumShouldMatch(queryParam.getLikeDegree())
        );
        MultiMatchQuery finalMultiMatchQuery = multiMatchQuery;
        tempBool.should(m -> m.multiMatch(finalMultiMatchQuery));
    }
    tempBool.minimumShouldMatch(queryParam.getLikeDegree());


    SearchRequest.Builder builder = new SearchRequest.Builder();
    RangeQuery rq;
    if (Strings.isNotBlank(queryParam.getStartDate()) && Strings.isNotBlank(
        queryParam.getEndDate())) {
      rq = RangeQuery.of(
          r -> r.field("news_publicdate").gte(JsonData.of(queryParam.getStartDate()))
              .lte(JsonData.of(queryParam.getEndDate())));
    } else if (Strings.isNotBlank(queryParam.getStartDate())) {
      rq = RangeQuery.of(
          r -> r.field("news_publicdate").gte(JsonData.of(queryParam.getStartDate())));
    } else if (Strings.isNotBlank(queryParam.getEndDate())) {
      rq = RangeQuery.of(
          r -> r.field("news_publicdate").lte(JsonData.of(queryParam.getEndDate())));
    } else {
      rq = null;
    }
    BoolQuery tempBoolQuery = tempBool.build();
    setNormal(builder, queryParam, queryStr, rq, tempBoolQuery, includes);

    return builder;
  }
}
